home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Toolbox / Menu Defproc 1.0.3 / PopUpTkl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-02  |  10.1 KB  |  245 lines  |  [TEXT/MPS ]

  1. /*============================================================================*\
  2. * PopUpTkl.c - Popup menu tackler
  3. *
  4. * PopUpTkl.c contains the code to process the mPopUpMsg message from the Menu
  5. * Manager.  This involves calculating the rectangle that the popup menu should
  6. * appear in.
  7. \*============================================================================*/
  8.  
  9.  
  10. /******************************************************************************\
  11. * Header Files
  12. \******************************************************************************/
  13.  
  14. #include <Memory.h>
  15. #include <Menus.h>
  16. #include <OSUtils.h>
  17. #include <Script.h>
  18. #include <Types.h>
  19. #include "Concordia.h"
  20. #include "DrawTkl.h"
  21. #include "PopUpTkl.h"
  22. #include "SizeTkl.h"
  23.  
  24.  
  25. /******************************************************************************\
  26. * Prototypes
  27. \******************************************************************************/
  28.  
  29. void FindScreen (Rect *menuRect,
  30.                  Rect *retScreenRect);
  31.  
  32.  
  33. #pragma segment Main
  34. /******************************************************************************\
  35. * DoPopUpMsg - Calculate a popup menu's rectangle
  36. *
  37. * DoPopUpMsg calculates the menu rectangle for the popup menu specified by
  38. * TheMenu.  This rectangle is returned in MenuRect.  The top-left corner of the
  39. * menu item specified by PopUpItem will appear at the coordinates given by
  40. * TopPos and LeftPos.  The vertical coordinate of the top of the menu's
  41. * rectangle is returned.  If the menu runs off of the screen, its size and
  42. * position will be adjusted.
  43. *
  44. * Coding Notes
  45. * #A# - This loop calculates the total height of the menu (Height), the width of
  46. *       the menu (Width), the height of the tallest item in the menu
  47. *       (MaxHeight), and the distance from the top of the menu to the item
  48. *       specified by PopUpItem (ItemPos).
  49. * #B# - Read this as: if the height of this menu is too small to display the
  50. *       tallest menu item and two scroll icons,then. . .
  51. * #C# - If the height of the tallest menu item plus two scroll icons is more
  52. *       than the height of the entire menu, adjust the menu's position so that
  53. *       the entire menu is displayed.  Otherwise, set the height of the menu to
  54. *       the height of the tallest item plus two scroll icons.
  55. \******************************************************************************/
  56.  
  57. short
  58. DoPopUpMsg (TheMenu, MenuRect, TopPos, LeftPos, PopUpItem)
  59.     MenuHandle TheMenu;   //=> Menu to size >>
  60.     Rect       *MenuRect; //-> Menu's rectangle <<
  61.     short      TopPos;    //Vertical screen position of popup item >>
  62.     short      LeftPos;   //Horizontal screen position of popup item >>
  63.     short      PopUpItem; //Item to appear at LeftPos, TopPos >>
  64.     {
  65.     Str255      *ItemString; //-> Item's string
  66.     ItemInfoPtr ItemInfo;    //-> Item info
  67.     short       TestWidth;   //Width of item to test
  68.     short       TestHeight;  //Width of menu to test
  69.     short       Height;      //Height of menu
  70.     short       Width;       //Width of menu
  71.     short       MaxHeight;   //Height of tallest menu item
  72.     short       ItemInd;     //Item number of item being checked.
  73.     short       ItemPos;     //Dist from menu top to PopUpItem in pixels
  74.     short       MenuTop;     //Coord of top of menu rect, even if off screen
  75.     Rect        ScrnRect;    //Rectangle of screen minus menu bar and margins
  76.     short       HeightAdj;   //New coord of menu top/bottom if small menu
  77.  
  78.     Height = Width = MaxHeight = 0;
  79.     ItemInd = 1;
  80.     ItemPos = 0;
  81.     HLock ((Handle) TheMenu);
  82.     ItemString = (Str255 *) (**TheMenu).menuData;
  83.     ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
  84.     while ((*ItemString) [0] != (char) 0) //#A#
  85.         {
  86.         ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize (*ItemString));
  87.         TestHeight = CalcItemHeight (*ItemString, ItemInfo);
  88.         TestWidth = CalcItemWidth (*ItemString, ItemInfo);
  89.         if (ItemInd == PopUpItem)
  90.             ItemPos = Height;
  91.         if (TestWidth > Width)
  92.             Width = TestWidth;
  93.         if (TestHeight > MaxHeight)
  94.             MaxHeight = TestHeight;
  95.         Height += TestHeight;
  96.         ItemInd += 1;
  97.         ItemString = (Str255 *) (ItemInfo + 1);
  98.         }
  99.     HUnlock ((Handle) TheMenu);
  100.     MenuTop = TopPos - ItemPos;
  101.     MenuRect->left = LeftPos;
  102.     MenuRect->top = MenuTop;
  103.     MenuRect->right = MenuRect->left + Width;
  104.     MenuRect->bottom = MenuRect->top + Height;
  105.     FindScreen (MenuRect, &ScrnRect);
  106.     InsetRect (&ScrnRect, scrnMargin, scrnMargin);
  107.     if (MenuRect->top < ScrnRect.top)
  108.         {
  109.         MenuRect->top = ScrnRect.top;
  110.         if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) <
  111.                 MaxHeight) //#B#
  112.             {
  113.             if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C#
  114.                 HeightAdj = MenuRect->top + Height;
  115.             else
  116.                 HeightAdj = MenuRect->top + MaxHeight + (short) (2 *
  117.                         scrlIconHeight);
  118.             MenuTop += HeightAdj - MenuRect->bottom;
  119.             MenuRect->bottom = HeightAdj;
  120.             }
  121.         }
  122.     if (MenuRect->right > ScrnRect.right)
  123.         OffsetRect (MenuRect, ScrnRect.right - MenuRect->right, 0);
  124.     if (MenuRect->left < ScrnRect.left)
  125.         OffsetRect (MenuRect, ScrnRect.left - MenuRect->left, 0);
  126.     if (MenuRect->bottom > ScrnRect.bottom)
  127.         {
  128.         MenuRect->bottom = ScrnRect.bottom;
  129.         if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) <
  130.                 MaxHeight) //#B#
  131.             {
  132.             if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C#
  133.                 HeightAdj = MenuRect->bottom - Height;
  134.             else
  135.                 HeightAdj = MenuRect->bottom - MaxHeight - (short) (2 *
  136.                         scrlIconHeight);
  137.             MenuTop -= MenuRect->top - HeightAdj;
  138.             MenuRect->top = HeightAdj;
  139.             }
  140.         }
  141.     return MenuTop;
  142.     }
  143.  
  144.  
  145. /******************************************************************************\
  146. * Private: FindScreen - Find rectangle of the screen containing most of the menu
  147. *
  148. * Color QuickDraw machines can have more than one screen, and pop-up menus
  149. * should appear on the screen that contains the most of the menu’s area.  This
  150. * function returns the rectangle of the screen (in global coordinates) that
  151. * contains most of the menu whose rectangle (also in global coordinates) is
  152. * passed in the menuRect parameter.  The screen’s rectangle is returned in the
  153. * retScreenRect parameter.  If the screen that contains the most of the menu is
  154. * the main screen (i.e. the screen with the menu bar), then the height of the
  155. * menu bar is added to the top of retScreenRect, effectively removing the menu
  156. * bar from the rectangle.  When Concordia is used on a machine without Color
  157. * QuickDraw, then the rectangle of the main screen is always returned.  Non-
  158. * Color QuickDraw machines with more than one screen (available from third-party
  159. * manufacturers) patch QuickDraw to support their screens, and it’s impossible
  160. * to determine the rectangles of the auxiliary screens without using
  161. * manufacturer-specific techniques.  Because of this, Concordia does not take
  162. * advantage of auxiliary screens on non-Color QuickDraw machines.
  163. *
  164. * The rectangles of all attached screens are determined through the GDevice list
  165. * that’s maintained by the system.  There’s one GDevice in the list for every
  166. * screen attached to the system.  GDevice routines only exist on Color QuickDraw
  167. * machines, so the first thing that FindScreen does is to determine whether it’s
  168. * running on a machine that has Color QuickDraw or not.  If it’s not, then the
  169. * screen rectangle is taken from the screenBits.bounds QuickDraw global.  If
  170. * Color QuickDraw is available, then the GDevice list is used to determine the
  171. * appropriate screen.
  172. *
  173. * The first GDevice in the GDevice list is retrieved from the GetDeviceList
  174. * function.  The next GDevice in the list is retrieved from the GetNextDevice
  175. * function.  Through these two functions, every GDevice in the GDevice list can
  176. * be retrieved.
  177. *
  178. * For every GDevice in the list, the area of intersection between the menu’s
  179. * rectangle and the screen’s rectangle (found in the gdRect field of the GDevice
  180. * structure) is calculated.  If the area of intersection is the greatest found
  181. * so far, then it and its GDevice is saved, and the rectangle of that screen is
  182. * placed into retScreenRect.
  183. *
  184. * After every GDevice in the GDevice list has been checked, the GDevice for the
  185. * screen containing most of the menu’s rectangle is checked to see if it’ the
  186. * GDevice for the main screen.  This is done by comparing the GDevice handle
  187. * against the handle for the main screen’s GDevice returned by GetMainDevice.
  188. * If the GDevice is in fact the main screen’s GDevice, then the height of the
  189. * menu bar is removed from retScreenRect.
  190. \******************************************************************************/
  191.  
  192. static void
  193. FindScreen (menuRect, retScreenRect)
  194.     Rect *menuRect;      /* Menu rectangle before processing for screen */
  195.     Rect *retScreenRect; /* Returns rectangle of screen appropriate for menu */
  196.     {
  197.     GDHandle  aGDevice;   /* Handle to each screen’s GDevice */
  198.     GDHandle  maxGDevice; /* Handle to GDevice containing most of menu */
  199.     long      area;       /* Menu rect/screen rect intersection area */
  200.     long      maxArea;    /* Max menu rect/screen rect intersect area found */
  201.     Rect      commonRect; /* Intersection between menu rect and screen rect */
  202.     SysEnvRec environs;   /* Current running environment */
  203.  
  204.     /* Determine whether Color QuickDraw is implemented or not */
  205.     (void) SysEnvirons (curSysEnvVers, /*<*/&environs);
  206.  
  207.     /* Use GDevices if Color QuickDraw is implemented, else use screenBits */
  208.     if (environs.hasColorQD)
  209.         {
  210.         /* Assume max intersection area is 0 and get first GDevice in list */
  211.         maxArea = 0L;
  212.         maxGDevice = nil;
  213.         aGDevice = GetDeviceList ();
  214.  
  215.         /* Loop through all screen GDevices */
  216.         while (aGDevice != nil)
  217.             {
  218.             /* Calc area of intersection between menu rect and screen rect */
  219.             SectRect (menuRect, &(**aGDevice).gdRect, /*<*/&commonRect);
  220.             area = (long) (commonRect.bottom - commonRect.top) * (commonRect.
  221.                     right - commonRect.left);
  222.  
  223.             /* If max area found so far, get screen’s rect and save area */
  224.             if (area > maxArea)
  225.                 {
  226.                 *retScreenRect = (**aGDevice).gdRect;
  227.                 maxGDevice = aGDevice;
  228.                 maxArea = area;
  229.                 }
  230.  
  231.             /* Go to the next GDevice in the list */
  232.             aGDevice = GetNextDevice (aGDevice);
  233.             }
  234.  
  235.         /* If GDevice with most of menu is main screen, remove MBar height */
  236.         if (maxGDevice == GetMainDevice ())
  237.             retScreenRect->top += GetMBarHeight ();
  238.         }
  239.     else
  240.         {
  241.         *retScreenRect = qdGlobPtr->screenBits.bounds;
  242.         retScreenRect->top += GetMBarHeight ();
  243.         }
  244.     }
  245.